#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <random>
#include <algorithm>
#include <cstring>

using namespace std;

const int SIZE = 9;
const int EMPTY = 0;
const char EMPTY_CHAR = '$';

bool isValid(const vector<vector<int>>& board, int row, int col, int num) {
    // 检查行是否合法
    for (int c = 0; c < SIZE; ++c) {
        if (board[row][c] == num) {
            return false;
        }
    }

    // 检查列是否合法
    for (int r = 0; r < SIZE; ++r) {
        if (board[r][col] == num) {
            return false;
        }
    }

    // 检查九宫格是否合法
    int startRow = 3 * (row / 3);
    int startCol = 3 * (col / 3);
    for (int r = 0; r < 3; ++r) {
        for (int c = 0; c < 3; ++c) {
            if (board[startRow + r][startCol + c] == num) {
                return false;
            }
        }
    }

    return true;
}

bool solveSudoku(vector<vector<int>>& board) {
    for (int r = 0; r < SIZE; ++r) {
        for (int c = 0; c < SIZE; ++c) {
            if (board[r][c] == EMPTY) {
                vector<int> nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
                random_device rd;
                mt19937 gen(rd());
                shuffle(nums.begin(), nums.end(), gen); // 洗牌

                for (int num : nums) {
                    if (isValid(board, r, c, num)) {
                        board[r][c] = num;
                        if (solveSudoku(board)) {
                            return true;
                        }
                        board[r][c] = EMPTY; // 恢复现场
                    }
                }
                return false;
            }
        }
    }
    return true;
}

void generateBlankCells(vector<vector<int>>& board, int numBlanks) {
    random_device rd;
    mt19937 gen(rd());
    uniform_int_distribution<> dis(0, SIZE - 1); // 随机选择挖空的位置

    int blanksCount = 0;
    while (blanksCount < numBlanks) {
        int row = dis(gen);
        int col = dis(gen);
        if (board[row][col] != EMPTY) {
            board[row][col] = EMPTY;
            blanksCount++;
        }
    }
}

void writeSudokuToFile(const vector<vector<int>>& board, ofstream& file) {
    for (const auto& row : board) {
        for (int num : row) {
            if (num != EMPTY) {
                file << num << " ";
            }
            else {
                file << EMPTY_CHAR << " ";
            }
        }
        file << endl;
    }
    file << endl; // 空一行
}

void writeSolutionToFile(const vector<vector<int>>& board, ofstream& file) {
    file << "数独局面：" << endl;
    writeSudokuToFile(board, file);
    file << "解：" << endl;
    vector<vector<int>> solvedBoard = board;
    if (solveSudoku(solvedBoard)) {
        writeSudokuToFile(solvedBoard, file);
    }
    else {
        file << "数独无解" << endl;
    }
    file << endl; // 空一行
}

bool readSudokuFromFile(vector<vector<int>>& board, ifstream& file) {
    for (int r = 0; r < SIZE; ++r) {
        for (int c = 0; c < SIZE; ++c) {
            char ch;
            file >> ch;
            if (ch == EMPTY_CHAR) {
                board[r][c] = EMPTY;
            }
            else {
                board[r][c] = ch - '0';
            }
        }
    }
    string emptyLine;
    getline(file, emptyLine); // 读取空行
    return true;
}

void generateSudoku(int numGames) {
    ofstream sudokuFile("legal_sudoku.txt");

    if (sudokuFile.is_open()) {
        random_device rd;
        mt19937 gen(rd());

        for (int game = 0; game < numGames; ++game) {
            vector<vector<int>> sudoku(SIZE, vector<int>(SIZE, 0));

            solveSudoku(sudoku);
            writeSudokuToFile(sudoku, sudokuFile);
        }

        sudokuFile.close();

        cout << "已成功生成数独终局并写入文件" << endl;
    }
    else {
        cout << "无法打开文件" << endl;
    }
}

void solveSudokuFromFile(const string& inputFile, const string& outputFile) {
    ifstream sudokuFile(inputFile);
    ofstream solutionFile(outputFile);

    if (sudokuFile.is_open() && solutionFile.is_open()) {
        int game = 1;
        while (!sudokuFile.eof()) {
            vector<vector<int>> sudoku(SIZE, vector<int>(SIZE, 0));
            readSudokuFromFile(sudoku, sudokuFile);

            solutionFile << "数独局面 " << game << ":" << endl;
            writeSolutionToFile(sudoku, solutionFile);

            ++game;
        }

        sudokuFile.close();
        solutionFile.close();

        cout << "数独解已成功写入文件" << endl;
    }
    else {
        cout << "无法打开文件" << endl;
    }
}

void generateSudokuWithBlanks(int numGames, int numBlanks) {
    ofstream sudokuFile("game.txt");

    if (sudokuFile.is_open()) {
        random_device rd;
        mt19937 gen(rd());

        for (int game = 0; game < numGames - 1; ++game) {
            vector<vector<int>> sudoku(SIZE, vector<int>(SIZE, 0));

            solveSudoku(sudoku);
            generateBlankCells(sudoku, numBlanks);

            writeSudokuToFile(sudoku, sudokuFile);
            sudokuFile << endl; // 空一行
        }

        // 处理最后一个局面
        vector<vector<int>> sudoku(SIZE, vector<int>(SIZE, 0));
        solveSudoku(sudoku);
        generateBlankCells(sudoku, numBlanks);

        // 写入最后一个局面，但不加入空行
        for (int r = 0; r < SIZE; ++r) {
            for (int c = 0; c < SIZE; ++c) {
                int num = sudoku[r][c];
                if (num != EMPTY) {
                    sudokuFile << num << " ";
                }
                else {
                    sudokuFile << EMPTY_CHAR << " ";
                }
            }
            if (r != SIZE - 1)
                sudokuFile << endl;
        }

        sudokuFile.close();

        cout << "已成功生成带空白格的数独局面并写入文件" << endl;
    }
    else {
        cout << "无法打开文件" << endl;
    }
}

int main(int argc, char* argv[]) {
    if (argc < 2) {
        cout << "参数不足" << endl;
        return 0;
    }

    string command = argv[1];

    if (command == "-c") {
        if (argc < 3) {
            cout << "缺少终局数量参数" << endl;
            return 0;
        }

        int numGames = stoi(argv[2]);
        if (numGames < 1 || numGames > 1000000) {
            cout << "终局数量超出范围" << endl;
            return 0;
        }

        generateSudoku(numGames);
    }
    else if (command == "-s") {
        string inputFile = "game.txt";
        string outputFile = "sudoku.txt";

        solveSudokuFromFile(inputFile, outputFile);
    }
    else if (command == "-n") {
        if (argc < 3) {
            cout << "缺少局面数量参数" << endl;
            return 0;
        }

        int numGames = stoi(argv[2]);
        if (numGames < 1 || numGames > 10000) {
            cout << "局面数量超出范围" << endl;
            return 0;
        }

        int numBlanks = 20; // 默认挖空数量为20

        if (argc >= 5 && strcmp(argv[3], "-r") == 0) {
            numBlanks = stoi(argv[4]);
            if (numBlanks < 20 || numBlanks > 55) {
                cout << "挖空数量超出范围" << endl;
                return 0;
            }
        }

        generateSudokuWithBlanks(numGames, numBlanks);
    }
    else {
        cout << "无效的命令" << endl;
    }

    return 0;
}
